//
// ConsumerParser.cpp for  in /home/herpec_j/Projets/
//
// Made by Jonathan
// Login   <herpec_j@epitech.net>
//
// Started on  Tue Sep 10 10:00:56 2013 Jonathan
// Last update Fri Sep 20 19:42:30 2013 Jonathan
//

#include	<sstream>
#include	<cstring>

#include	"Parsing/ConsumerParser.hpp"

namespace	Parsing
{
  ConsumerParser::ConsumerParser(ProducterStream &rStream) : mStream(rStream)
  {
    mCol = -1;
  }

  void		ConsumerParser::SaveContext(void)
  {
    try
      {
	FeedBuffer();
	mStack.push(mCol);
      }
    catch (std::exception const &e)
      {
	return;
      }
  }

  void		ConsumerParser::RestoreContext(bool rRestore)
  {
    if (!mStack.empty())
      {
	if (rRestore)
	  {
	    mCol = mStack.top();
	  }
	mStack.pop();
      }
  }

  bool		ConsumerParser::FeedBuffer(void)
  {
    if (mCol == -1 || mCol >= (int) mBuffer.size())
      {
	try
	  {
	    mBuffer += mStream.NextString();
	    if (mCol == -1)
	      {
		mCol = 0;
	      }
	    return (true);
	  }
	catch (std::exception const &e)
	  {
	    return (false);
	  }
      }
    return (true);
  }

  bool		ConsumerParser::PeekChar(char rC)
  {
    if (ReadEOF())
      {
	return (false);
      }
    if (mBuffer[mCol] == rC)
      {
	return (true);
      }
    else
      {
	return (false);
      }
  }

  bool		ConsumerParser::SkipSpaces(void)
  {
    ZERO_OR_MANY(ReadChar(' ', false) || ReadChar('\t', false) || ReadChar('\n', false));
    return (true);
  }

  bool		ConsumerParser::Read(void)
  {
    if (ReadEOF())
      {
	return (false);
      }
    ++mCol;
    return (true);
  }

  bool		ConsumerParser::ReadChar(char rC, bool rSkipSpaces)
  {
    SaveContext();
    if (rSkipSpaces)
      {
	SkipSpaces();
      }
    if (PeekChar(rC))
      {
	++mCol;
	RestoreContext(false);
	return (true);
      }
    else
      {
	RestoreContext(true);
	return (false);
      }
  }

  bool		ConsumerParser::ReadRange(char rBegin, char rEnd, bool rSkipSpaces)
  {
    SaveContext();
    if (rSkipSpaces)
      {
	SkipSpaces();
      }
    if (ReadEOF())
      {
	RestoreContext(true);
	return (false);
      }
    if (rEnd > rBegin && mBuffer[mCol] >= rBegin && mBuffer[mCol] <= rEnd)
      {
	++mCol;
	RestoreContext(false);
	return (true);
      }
    else
      {
	RestoreContext(true);
	return (false);
      }
  }

  bool		ConsumerParser::ReadText(char *rText, bool rSkipSpaces)
  {
    SaveContext();
    if (rSkipSpaces)
      {
	SkipSpaces();
      }
    if (ReadEOF())
      {
	RestoreContext(true);
	return (false);
      }
    if (mBuffer.substr(mCol, strlen(rText)) == std::string(rText))
      {
	mCol += strlen(rText);
	RestoreContext(false);
	return (true);
      }
    else
      {
	RestoreContext(true);
	return (false);
      }
  }

  bool		ConsumerParser::ReadEOF(void)
  {
    return (!FeedBuffer());
  }

  bool		ConsumerParser::ReadUntil(char rC)
  {
    SaveContext();
    while (!ReadEOF())
      {
	if (PeekChar(rC))
	  {
	    RestoreContext(false);
	    return (true);
	  }
	else
	  {
	    ++mCol;
	  }
      }
    RestoreContext(true);
    return (false);
  }

  bool		ConsumerParser::ReadUntil(std::list<char> const &rCharList)
  {
    SaveContext();
    while (!ReadEOF())
      {
	for (std::list<char>::const_iterator it = rCharList.begin();
	     it != rCharList.end();
	     ++it)
	  {
	    if (PeekChar(*it))
	      {
		RestoreContext(false);
		return (true);
	      }
	  }
	++mCol;
      }
    RestoreContext(true);
    return (false);
  }

  bool		ConsumerParser::ReadUntilEOF(void)
  {
    while (!ReadEOF())
      {
	++mCol;
      }
    return (true);
  }

  bool		ConsumerParser::ReadInteger(bool rSkipSpaces)
  {
    if (rSkipSpaces)
      {
	SkipSpaces();
      }
    ZERO_OR_ONE(ReadChar('-'));
    ONE_OR_MANY(ReadRange('0', '9'));
    return (true);
  }

  bool		ConsumerParser::ReadIdentifier(bool rSkipSpaces)
  {
    SaveContext();
    if (rSkipSpaces)
      {
	SkipSpaces();
      }
    if (ReadRange('a', 'z') || ReadRange('A', 'Z') || ReadChar('_'))
      {
	ZERO_OR_MANY(ReadRange('0', '9') || ReadRange('a', 'z') || ReadRange('A', 'Z') || ReadChar('_'));
	RestoreContext(false);
	return (true);
      }
    RestoreContext(true);
    return (false);
  }

  bool		ConsumerParser::BeginCapture(std::string rTag, bool rSkipSpaces)
  {
    if (rSkipSpaces)
      {
	SkipSpaces();
      }
    if (ReadEOF())
      {
	return (false);
      }
    else
      {
	mMap[rTag] = mCol;
	return (true);
      }
  }

  bool		ConsumerParser::EndCapture(std::string rTag, std::string &rOut)
  {
    std::map<std::string, int>::iterator it = mMap.find(rTag);

    if (it != mMap.end())
      {
	bool	return_value = true;

	if (mCol == it->second)
	  {
	    return_value = false;
	  }
	else
	  {
	    rOut = mBuffer.substr(it->second, mCol - it->second);
	  }
	mMap.erase(rTag);
	return (return_value);
      }
    else
      {
	return (false);
      }
  }

  ConsumerParser::~ConsumerParser(void)
  {
    return;
  }
};
